package com.lingjtx.auth.aop;

import com.lingjtx.common.captcha.CaptchaGenerator;
import com.lingjtx.common.captcha.CaptchaType;
import com.lingjtx.common.captcha.NeedCaptcha;
import com.lingjtx.common.core.constant.Const;
import com.lingjtx.common.core.constant.RedisConfig;
import com.lingjtx.common.core.constant.ResponseTip;
import com.lingjtx.common.core.exception.CaptchaException;
import com.lingjtx.common.core.exception.ResponseErrorException;
import com.lingjtx.common.core.util.BeanUtil;
import com.lingjtx.common.core.util.StringUtil;
import com.lingjtx.common.redis.service.IRedisService;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

@Slf4j
@Order(3)
@Component
@Aspect
public class NeedCaptchaAspect {

    private final IRedisService redisService;

    public NeedCaptchaAspect(IRedisService redisService) {
        this.redisService = redisService;
    }

    @Before("@annotation(com.lingjtx.common.captcha.NeedCaptcha)")
    public void interceptor(JoinPoint point) {
        MethodSignature signature = (MethodSignature) point.getSignature();
        NeedCaptcha annotation = signature.getMethod().getAnnotation(NeedCaptcha.class);
        if (Objects.nonNull(annotation)) {
            HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
            // 首先有二次验证值（验证码code值），直接根据验证码类型二次校验校验：正确放行，否则校验错误
            // 没有二次验证值，根据注解的num值是否警告值，超过的话，需要验证码，没有超过正常放行
            Object[] args = point.getArgs();
            if (Objects.nonNull(args) && args.length > 0) {
                Map<String, Object> map = BeanUtil.covertMap(args[0]);
                if (map != null) {
                    String captchaType = (String) map.get("captchaType");
                    String authenticate = (String) map.get("authenticate");
                    String captchaUid = (String) map.get("captchaUid");
                    if (StringUtil.isNotEmpty(captchaType)
                            && StringUtil.isNotEmpty(captchaUid)
                            && StringUtil.isNotEmpty(authenticate)) {// 有二次校验值
                        if (CaptchaType.VERIFY_CODE.getValue().equals(captchaType)) {
                            String code = (String) redisService.get("captcha:verify:code:" + request.getSession().getId());
                            if (!authenticate.equals(code)) {
                                throw new ResponseErrorException("验证码错误，请重试");
                            }
                        } else {
                            if (!CaptchaGenerator.verify(captchaUid, authenticate, redisService)) {
                                throw new ResponseErrorException("二次校验令牌错误");
                            }
                        }
                    } else {
                        String rdsKey = RedisConfig.KEY_API_CAPTCHA_COUNT +
                                request.getRequestURI() + ":" +
                                request.getSession().getId();
                        int num = redisService.increment(rdsKey).intValue();
                        if (Objects.equals(1, num)) { // 新增
                            redisService.expire(rdsKey, annotation.expire());
                        }
                        if (num <= annotation.nums()) { // true-超过警告值；false-在安全值内
                            return;
                        }
                        Map<String, String> result = new HashMap<>(2);
                        result.put("captchaType", annotation.type().toString());
                        if (!CaptchaType.VERIFY_CODE.equals(annotation.type())) {
                            result.put("h5", Const.SERVER_URL + "/user/captcha/h5/" + annotation.type());
                        }
                        throw new CaptchaException(ResponseTip.RESPONSE_BODY_CAPTCHA, result);
                    }
                }
            }
        }
    }

}
